package com.example.routeplansystem.algorithm.imp;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.ServerException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.example.routeplansystem.algorithm.Algorithm;
import com.example.routeplansystem.dao.EdgesDao;
import com.example.routeplansystem.dao.NodeDao;
import com.example.routeplansystem.dao.ProgramDao;
import com.example.routeplansystem.dao.QuestionNodeDao;
import com.example.routeplansystem.entity.po.Edges;
import com.example.routeplansystem.entity.po.FinalSolution;
import com.example.routeplansystem.entity.po.NodePojo;
import com.example.routeplansystem.entity.po.Program;
import com.example.routeplansystem.entity.po.QuestionNodePojo;
import com.example.routeplansystem.entity.po.Solution;
import com.example.routeplansystem.entity.po.VehicleMessage;
import com.example.routeplansystem.service.impl.WebSocketService;
import com.example.routeplansystem.utils.DistanceUtil;

/**
 * @Author lucong
 * @Date 2022/10/31
 * @Description
 */
@Component
public class UserAlgorithm implements Algorithm {

    @Value("${algorithm.file.path}")
    private String path;

    @Autowired
    private EdgesDao edgesDao;

    @Autowired
    private QuestionNodeDao questionNodeDao;

    @Autowired
    private NodeDao nodeDao;

    @Autowired
    private ProgramDao programDao;

    @Override
    public List<Solution> getSolution(List<NodePojo> nodes, List<NodePojo> centerNodes, List<VehicleMessage> vehicles
            , FinalSolution fs) throws ServerException {
        NodePojo center = centerNodes.get(0);//只能处理一个中心点
        nodes.add(0, center); // 将中心点放在最前面
        generateProblemFile(nodes, fs.getFinalSolutionId());
        runAlgorithm(fs);
        VehicleMessage vehicle = vehicles.get(0);// 只能处理一辆车
        return Collections.EMPTY_LIST;
    }

    private void runAlgorithm(FinalSolution fs){
        Program program = programDao.getProgramById(fs.getVersion());
        BufferedReader br = null;
        BufferedReader brError = null;
        try { // 运行用户自定义的文件
            ProcessBuilder processBuilder = new ProcessBuilder(program.getCommand());
            File dir = new File(path + File.separator +  "question" + fs.getFinalSolutionId());
            processBuilder.directory(dir);
            Process p = processBuilder.start();
            String line = null;
            //获得子进程的输入流。
            br = new BufferedReader(new InputStreamReader(p.getInputStream()));
            brError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            p.getOutputStream().close(); // 关闭输出流防止程序挂起无法结束
            while ((line = br.readLine()) != null || (line = brError.readLine()) != null) {
                //输出exe输出的信息以及错误信息
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void checkMatrix(Integer questionId, Integer finalSolutionId) {
        List<QuestionNodePojo> questionNode = questionNodeDao.selectAllNode(questionId);
        List<Integer> nodeIds = questionNode.stream().map(QuestionNodePojo::getNodeId).collect(Collectors.toList());
        Map<Integer, NodePojo> nodeMap = nodeDao.selectNodeByIdList(nodeIds).stream().collect(Collectors.toMap(NodePojo::getNodeId, n -> n));
        List<NodePojo> nodes = questionNode.stream().map(n -> nodeMap.get(n.getNodeId())).collect(Collectors.toList());
        int n = nodes.size();
        List<Integer> list = nodes.stream().map(NodePojo::getNodeId).collect(Collectors.toList());
        List<Edges> edges = edgesDao.findNodes(list);
        HashMap<Integer, Integer> map = new HashMap<>(n);
        for (int i = 0; i < n; i++) {
            map.put(list.get(i), i);
        }
        int[][] matrix = new int[n][n];
        for (Edges node : edges) {
            int i = map.get(node.getFromNode());
            int j = map.get(node.getToNode());
            matrix[i][j] = node.getDistance();
        }
        int count = 0;
        WebSocketService webSocketService = new WebSocketService();
        for (int i = 0; i < matrix.length; i++) {
            //发送进度
            webSocketService.sendToUser(finalSolutionId + "|" + String.format("%.2f", i * 100.0 / matrix.length));

            for (int j = 0; j < matrix[i].length; j++) {
                if (i == j) continue;
                if (matrix[i][j] == 0) {
                    Integer distance = DistanceUtil.getDistance(nodes.get(i), nodes.get(j));
                    System.out.println("第" + (count++) + "条数据:" + list.get(i) + "-" + list.get(j) + ":" + distance);
                }
            }
        }
        webSocketService.onClose(finalSolutionId + "");
    }

    /**
     * @description : 构建atsp问题文件
     */
    private void generateProblemFile(List<NodePojo> nodes, Integer finalSolutionId) {
        // 获得矩阵
        int n = nodes.size();
        List<Integer> list = nodes.stream().map(NodePojo::getNodeId).collect(Collectors.toList());
        List<Edges> edges = edgesDao.findNodes(list);
        HashMap<Integer, Integer> map = new HashMap<>(n);
        for (int i = 0; i < n; i++) {
            map.put(list.get(i), i);
        }
        int[][] matrix = new int[n][n];
        for (Edges node : edges) {
            int i = map.get(node.getFromNode());
            int j = map.get(node.getToNode());
            matrix[i][j] = node.getDistance();
        }
        // 构造文件
        String filePath = path + File.separator + "question" + finalSolutionId + File.separator + "question" + finalSolutionId + ".atsp";
        try (FileWriter fw = new FileWriter(filePath)) {
            fw.write("");//清空数据
            fw.append("NAME : solution" + finalSolutionId + "\r\n");
            fw.append("COMMENT : route plan problem ()" + new Date().toString() + "\r\n");
            fw.append("TYPE : ATSP" + "\r\n");
            fw.append("DIMENSION : " + nodes.size() + "\r\n");
            fw.append("EDGE_WEIGHT_TYPE : EXPLICIT" + "\r\n");
            fw.append("EDGE_WEIGHT_FORMAT : FULL_MATRIX" + "\r\n");
            fw.append("EDGE_WEIGHT_SECTION" + "\r\n");
            for (int[] cols : matrix) {
                StringBuilder sb = new StringBuilder();
                for (int weight : cols) {
                    sb.append(weight);
                    sb.append(" ");
                }
                System.out.println(sb);
                fw.append(sb.append("\r\n"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
